home *** CD-ROM | disk | FTP | other *** search
/ Aminet 40 / Aminet 40 (2000)(Schatztruhe)[!][Dec 2000].iso / Aminet / dev / lang / Python16.lha / Python-1.6 / Lib / Python1.6 / gzip.py < prev    next >
Encoding:
Python Source  |  2000-05-08  |  11.0 KB  |  344 lines

  1. """Functions that read and write gzipped files.
  2.  
  3. The user of the file doesn't have to worry about the compression,
  4. but random access is not allowed."""
  5.  
  6. # based on Andrew Kuchling's minigzip.py distributed with the zlib module
  7.  
  8. import time
  9. import string
  10. import zlib
  11. import struct
  12. import __builtin__
  13.  
  14. FTEXT, FHCRC, FEXTRA, FNAME, FCOMMENT = 1, 2, 4, 8, 16
  15.  
  16. READ, WRITE = 1, 2
  17.  
  18. def write32(output, value):
  19.     output.write(struct.pack("<l", value))
  20.     
  21. def write32u(output, value):
  22.     output.write(struct.pack("<L", value))
  23.  
  24. def read32(input):
  25.     return struct.unpack("<l", input.read(4))[0]
  26.  
  27. def open(filename, mode="rb", compresslevel=9):
  28.     return GzipFile(filename, mode, compresslevel)
  29.  
  30. class GzipFile:
  31.  
  32.     myfileobj = None
  33.  
  34.     def __init__(self, filename=None, mode=None, 
  35.                  compresslevel=9, fileobj=None):
  36.         if fileobj is None:
  37.             fileobj = self.myfileobj = __builtin__.open(filename, mode or 'rb')
  38.         if filename is None:
  39.             if hasattr(fileobj, 'name'): filename = fileobj.name
  40.             else: filename = ''
  41.         if mode is None:
  42.             if hasattr(fileobj, 'mode'): mode = fileobj.mode
  43.             else: mode = 'rb'
  44.  
  45.         if mode[0:1] == 'r':
  46.             self.mode = READ
  47.          # Set flag indicating start of a new member
  48.             self._new_member = 1 
  49.             self.extrabuf = ""
  50.             self.extrasize = 0
  51.             self.filename = filename
  52.  
  53.         elif mode[0:1] == 'w' or mode[0:1] == 'a':
  54.             self.mode = WRITE
  55.             self._init_write(filename)
  56.             self.compress = zlib.compressobj(compresslevel,
  57.                                              zlib.DEFLATED, 
  58.                                              -zlib.MAX_WBITS,
  59.                                              zlib.DEF_MEM_LEVEL,
  60.                                              0)
  61.         else:
  62.             raise ValueError, "Mode " + mode + " not supported"
  63.  
  64.         self.fileobj = fileobj
  65.  
  66.         if self.mode == WRITE:
  67.             self._write_gzip_header()
  68.  
  69.     def __repr__(self):
  70.         s = repr(self.fileobj)
  71.         return '<gzip ' + s[1:-1] + ' ' + hex(id(self)) + '>'
  72.  
  73.     def _init_write(self, filename):
  74.         if filename[-3:] != '.gz':
  75.             filename = filename + '.gz'
  76.         self.filename = filename
  77.         self.crc = zlib.crc32("")
  78.         self.size = 0
  79.         self.writebuf = []
  80.         self.bufsize = 0
  81.  
  82.     def _write_gzip_header(self):
  83.         self.fileobj.write('\037\213')             # magic header
  84.         self.fileobj.write('\010')                 # compression method
  85.         fname = self.filename[:-3]
  86.         flags = 0
  87.         if fname:
  88.             flags = FNAME
  89.         self.fileobj.write(chr(flags))
  90.         write32u(self.fileobj, long(time.time()))
  91.         self.fileobj.write('\002')
  92.         self.fileobj.write('\377')
  93.         if fname:
  94.             self.fileobj.write(fname + '\000')
  95.  
  96.     def _init_read(self):
  97.         self.crc = zlib.crc32("")
  98.         self.size = 0
  99.  
  100.     def _read_gzip_header(self):
  101.         magic = self.fileobj.read(2)
  102.         if magic != '\037\213':
  103.             raise IOError, 'Not a gzipped file'
  104.         method = ord( self.fileobj.read(1) )
  105.         if method != 8:
  106.             raise IOError, 'Unknown compression method'
  107.         flag = ord( self.fileobj.read(1) )
  108.         # modtime = self.fileobj.read(4)
  109.         # extraflag = self.fileobj.read(1)
  110.         # os = self.fileobj.read(1)
  111.         self.fileobj.read(6)
  112.  
  113.         if flag & FEXTRA:
  114.             # Read & discard the extra field, if present
  115.             xlen=ord(self.fileobj.read(1))              
  116.             xlen=xlen+256*ord(self.fileobj.read(1))
  117.             self.fileobj.read(xlen)
  118.         if flag & FNAME:
  119.             # Read and discard a null-terminated string containing the filename
  120.             while (1):
  121.                 s=self.fileobj.read(1)
  122.                 if not s or s=='\000': break
  123.         if flag & FCOMMENT:
  124.             # Read and discard a null-terminated string containing a comment
  125.             while (1):
  126.                 s=self.fileobj.read(1)
  127.                 if not s or s=='\000': break
  128.         if flag & FHCRC:
  129.             self.fileobj.read(2)     # Read & discard the 16-bit header CRC
  130.  
  131.  
  132.     def write(self,data):
  133.         if self.fileobj is None:
  134.             raise ValueError, "write() on closed GzipFile object"
  135.         if len(data) > 0:
  136.             self.size = self.size + len(data)
  137.             self.crc = zlib.crc32(data, self.crc)
  138.             self.fileobj.write( self.compress.compress(data) )
  139.  
  140.     def writelines(self,lines):
  141.         self.write(string.join(lines))
  142.  
  143.     def read(self, size=-1):
  144.         if self.extrasize <= 0 and self.fileobj is None:
  145.             return ''
  146.  
  147.         readsize = 1024
  148.         if size < 0:        # get the whole thing
  149.             try:
  150.                 while 1:
  151.                     self._read(readsize)
  152.                     readsize = readsize * 2
  153.             except EOFError:
  154.                 size = self.extrasize
  155.         else:               # just get some more of it
  156.             try:
  157.                 while size > self.extrasize:
  158.                     self._read(readsize)
  159.                     readsize = readsize * 2
  160.             except EOFError:
  161.                 if size > self.extrasize:
  162.                     size = self.extrasize
  163.         
  164.         chunk = self.extrabuf[:size]
  165.         self.extrabuf = self.extrabuf[size:]
  166.         self.extrasize = self.extrasize - size
  167.  
  168.         return chunk
  169.  
  170.     def _unread(self, buf):
  171.         self.extrabuf = buf + self.extrabuf
  172.         self.extrasize = len(buf) + self.extrasize
  173.  
  174.     def _read(self, size=1024):
  175.         if self.fileobj is None: raise EOFError, "Reached EOF"
  176.      
  177.         if self._new_member:
  178.             # If the _new_member flag is set, we have to 
  179.             # 
  180.             # First, check if we're at the end of the file;
  181.             # if so, it's time to stop; no more members to read.
  182.             pos = self.fileobj.tell()   # Save current position
  183.             self.fileobj.seek(0, 2)     # Seek to end of file
  184.             if pos == self.fileobj.tell():
  185.                 self.fileobj = None
  186.                 raise EOFError, "Reached EOF"
  187.             else: 
  188.                 self.fileobj.seek( pos ) # Return to original position
  189.   
  190.             self._init_read()       
  191.             self._read_gzip_header()
  192.             self.decompress = zlib.decompressobj(-zlib.MAX_WBITS)
  193.             self._new_member = 0
  194.  
  195.         # Read a chunk of data from the file
  196.         buf = self.fileobj.read(size)
  197.  
  198.         # If the EOF has been reached, flush the decompression object
  199.         # and mark this object as finished.
  200.        
  201.         if buf == "":
  202.             uncompress = self.decompress.flush()
  203.             self._read_eof()
  204.             self.fileobj = None
  205.             self._add_read_data( uncompress )
  206.             raise EOFError, 'Reached EOF'
  207.   
  208.         uncompress = self.decompress.decompress(buf)
  209.         self._add_read_data( uncompress )
  210.  
  211.         if self.decompress.unused_data != "":
  212.             # Ending case: we've come to the end of a member in the file,
  213.             # so seek back to the start of the unused data, finish up
  214.             # this member, and read a new gzip header.
  215.             # (The number of bytes to seek back is the length of the unused
  216.             # data, minus 8 because _read_eof() will rewind a further 8 bytes)
  217.             self.fileobj.seek( -len(self.decompress.unused_data)+8, 1)
  218.  
  219.             # Check the CRC and file size, and set the flag so we read
  220.             # a new member on the next call 
  221.             self._read_eof()
  222.             self._new_member = 1        
  223.         
  224.     def _add_read_data(self, data):            
  225.         self.crc = zlib.crc32(data, self.crc)
  226.         self.extrabuf = self.extrabuf + data
  227.         self.extrasize = self.extrasize + len(data)
  228.         self.size = self.size + len(data)
  229.  
  230.     def _read_eof(self):
  231.         # We've read to the end of the file, so we have to rewind in order
  232.         # to reread the 8 bytes containing the CRC and the file size.  
  233.         # We check the that the computed CRC and size of the
  234.         # uncompressed data matches the stored values.
  235.         self.fileobj.seek(-8, 1)
  236.         crc32 = read32(self.fileobj)
  237.         isize = read32(self.fileobj)
  238.         if crc32%0x100000000L != self.crc%0x100000000L:
  239.             raise ValueError, "CRC check failed"
  240.         elif isize != self.size:
  241.             raise ValueError, "Incorrect length of data produced"
  242.           
  243.     def close(self):
  244.         if self.mode == WRITE:
  245.             self.fileobj.write(self.compress.flush())
  246.             write32(self.fileobj, self.crc)
  247.             write32(self.fileobj, self.size)
  248.             self.fileobj = None
  249.         elif self.mode == READ:
  250.             self.fileobj = None
  251.         if self.myfileobj:
  252.             self.myfileobj.close()
  253.             self.myfileobj = None
  254.  
  255.     def __del__(self):
  256.         try:
  257.             if (self.myfileobj is None and
  258.                 self.fileobj is None):
  259.                 return
  260.         except AttributeError:
  261.             return
  262.         self.close()
  263.         
  264.     def flush(self):
  265.         self.fileobj.flush()
  266.  
  267.     def seek(self):
  268.         raise IOError, 'Random access not allowed in gzip files'
  269.  
  270.     def tell(self):
  271.         raise IOError, 'I won\'t tell() you for gzip files'
  272.  
  273.     def isatty(self):
  274.         return 0
  275.  
  276.     def readline(self):
  277.         bufs = []
  278.         readsize = 100
  279.         while 1:
  280.             c = self.read(readsize)
  281.             i = string.find(c, '\n')
  282.             if i >= 0 or c == '':
  283.                 bufs.append(c[:i+1])
  284.                 self._unread(c[i+1:])
  285.                 return string.join(bufs, '')
  286.             bufs.append(c)
  287.             readsize = readsize * 2
  288.  
  289.     def readlines(self, ignored=None):
  290.         buf = self.read()
  291.         lines = string.split(buf, '\n')
  292.         for i in range(len(lines)-1):
  293.             lines[i] = lines[i] + '\n'
  294.         if lines and not lines[-1]:
  295.             del lines[-1]
  296.         return lines
  297.  
  298.     def writelines(self, L):
  299.         for line in L:
  300.             self.write(line)
  301.  
  302.  
  303. def _test():
  304.     # Act like gzip; with -d, act like gunzip.
  305.     # The input file is not deleted, however, nor are any other gzip
  306.     # options or features supported.
  307.     import sys
  308.     args = sys.argv[1:]
  309.     decompress = args and args[0] == "-d"
  310.     if decompress:
  311.         args = args[1:]
  312.     if not args:
  313.         args = ["-"]
  314.     for arg in args:
  315.         if decompress:
  316.             if arg == "-":
  317.                 f = GzipFile(filename="", mode="rb", fileobj=sys.stdin)
  318.                 g = sys.stdout
  319.             else:
  320.                 if arg[-3:] != ".gz":
  321.                     print "filename doesn't end in .gz:", `arg`
  322.                     continue
  323.                 f = open(arg, "rb")
  324.                 g = __builtin__.open(arg[:-3], "wb")
  325.         else:
  326.             if arg == "-":
  327.                 f = sys.stdin
  328.                 g = GzipFile(filename="", mode="wb", fileobj=sys.stdout)
  329.             else:
  330.                 f = __builtin__.open(arg, "rb")
  331.                 g = open(arg + ".gz", "wb")
  332.         while 1:
  333.             chunk = f.read(1024)
  334.             if not chunk:
  335.                 break
  336.             g.write(chunk)
  337.         if g is not sys.stdout:
  338.             g.close()
  339.         if f is not sys.stdin:
  340.             f.close()
  341.  
  342. if __name__ == '__main__':
  343.     _test()
  344.